//VARS DECLARATION
#define filterSamples   7              // filterSamples should  be an odd number, no smaller than 3
int numInputs = 6;
int numKnobs = 2;
int baudRate = 9600;

//ARRAYS FOR THE SMOTHING AND SHAPING ALGORITHMS
int analogInputValue[6] = {0,0,0,0,0,0};
int analogInputSmooth[6] = {0,0,0,0,0,0};
int analogInputShaped[6] = {0,0,0,0,0,0};
int analogSmoothArray[6][filterSamples];

//AN ARRAY OF INTERGERS REPRESENTING THE DIGITAL PINS OF THE LEDS
int knob_leds[2] = {9,10};

//A COUNTER INTEGER
int n;

//SERIAL INTEGER TO BYTE
                // 0   1   2   3   4   5   6   7
int binOut [] = {000,  1, 10, 11,100,101,110,111};
               // 4   6   2   1   7   5   0   3
int binIn [] =  {100,110, 10,  1,111,101,000, 11};
char inByte = 'B';
byte msB, lsB;
int serialInCount = 0;

//SETS UP THE PINS BY USING THE COUNTER n TO ASSIGN THE THE NUMBERS IN numKnobs, numInputs TO EITHER INPUT OR OUTPUT SELECTION OF LED PINS VIA knob_leds ARRAY.   ALLOWS FOR EASY CHANGING OF EITHER VALUE AT DECLARATION (TOP OF DOC).  SETS THE BAUD RATE REQUIRED.
void setup() {
  for (n = 0;n<numInputs;n++) pinMode(n, INPUT);
  for (n = 0;n<numKnobs;n++) pinMode(knob_leds[n], OUTPUT);

  // open the serial port at bps defined in var declaration section:
  Serial.begin(baudRate);
}

//RECIEVES ANY SERIAL DATA SENT FROM PROCESSING, SENDS THE SMOOTHED ANALOG VALUES TO PROCESSING AND UPDATES THE LEDS BASED ON THE SAME VALUE.
void loop() {

  // read the value on analog input
  if (Serial.available() > 0) {
    inByte = Serial.read();

    if (inByte == 'A') {  
      
    for (n = 0;n<numInputs;n++) {
        analogInputValue[n] = analogRead(n);  											  //gets the value of the analog pin
        analogInputSmooth[n] = digitalSmooth(analogInputValue[n], analogSmoothArray[n]);  //sets up the smooth by passing to digital smooth
        if (analogInputSmooth[n] < 150)													  //smooths data even more below a raw input of 150	
            analogInputSmooth[n] = digitalSmooth(analogInputValue[n], analogSmoothArray[n]);
        if (analogInputSmooth[n] < 30)									 //cuts the lowest data to zero (we used to blank led so as not to break the pots)
            analogInputSmooth[n] = 0;
        //analogInputShaped[n] = shapeData(analogInputSmooth[n]);
        delay(5);
      }
      //sends the data over the serial in a Proc33ing friendly fashion.
      for (n = 0;n<numInputs;n++) {
        msB = byte((analogInputSmooth[n] & 65280) >> 8);                     // 65280 = 0b1111111100000000
        lsB = byte(analogInputSmooth[n] & 255);                              // 255 =   0b0000000011111111
        Serial.print(msB,BYTE);
        Serial.print(lsB,BYTE);        
      }
	  //sets the brightness level of the led to the value of the smoothed input.
      for (n = 0;n<numKnobs;n++) {
        analogWrite(knob_leds[n], analogInputSmooth[n]/4);
      }
     }
  }
}

//DIGITAL SMOOTHING ALGO, CARE OF - http://www.arduino.cc/playground/Main/DigitalSmooth
int digitalSmooth(int rawIn, int *sensSmoothArray){     // "int *sensSmoothArray" passes an array to the function - the asterisk indicates the array name is a pointer
  int j, k, temp, top, bottom;
  long total;
  static int i;
 // static int raw[filterSamples];
  static int sorted[filterSamples];
  boolean done;

  i = (i + 1) % filterSamples;    // increment counter and roll over if necc. -  % (modulo operator) rolls over variable
  sensSmoothArray[i] = rawIn;                 // input new data into the oldest slot

  // Serial.print("raw = ");

  for (j=0; j<filterSamples; j++){     // transfer data array into anther array for sorting and averaging
    sorted[j] = sensSmoothArray[j];
  }

  done = 0;                // flag to know when we're done sorting              
  while(done != 1){        // simple swap sort, sorts numbers from lowest to highest
    done = 1;
    for (j = 0; j < (filterSamples - 1); j++){
      if (sorted[j] > sorted[j + 1]){     // numbers are out of order - swap
        temp = sorted[j + 1];
        sorted [j+1] =  sorted[j] ;
        sorted [j] = temp;
        done = 0;
      }
    }
  }

  // throw out top and bottom 15% of samples - limit to throw out at least one from top and bottom
  bottom = max(((filterSamples * 15)  / 100), 1); 
  top = min((((filterSamples * 85) / 100) + 1  ), (filterSamples - 1));   // the + 1 is to make up for asymmetry caused by integer rounding
  k = 0;
  total = 0;
  for ( j = bottom; j< top; j++){
    total += sorted[j];  // total remaining indices
    k++; 
  }

  return total / k;    // divide by number of samples
}

//int shapeData(int data){
//  float fl = (float)data / ( 1024.0 / log(1024) );
//  float flExp = ((float) exp(fl) );
//  return int(flExp);
//}
